package org.kaleido.client;

import org.kaleido.client.activity.mapper.DataPanelActivityMapper;
import org.kaleido.client.place.AppPlaceHistoryMapper;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.activity.shared.ActivityManager;
import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.event.shared.UmbrellaException;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.place.shared.PlaceHistoryHandler;
import com.google.gwt.user.client.Window;

/**
 * Default implementation of {@link ClientFactory}. Used by desktop version.
 */
public class ClientFactoryImpl implements ClientFactory {

    private final EventBus eventBus = new SimpleEventBus();
    private final PlaceController placeController = new PlaceController(eventBus);
    private ActivityManager activityManager;
    private final AppPlaceHistoryMapper historyMapper = GWT.create(AppPlaceHistoryMapper.class);
    private final PlaceHistoryHandler  historyHandler = new PlaceHistoryHandler(historyMapper);
    public ClientFactoryImpl() {
        initializeExceptionHandler();
    }
    

    @Override
    public EventBus getEventBus() {
        return eventBus;
    }

    @Override
    public PlaceController getPlaceController() {
        return placeController;
    }
    
    @Override
    public KaleidoApplication getApplication() {
        return new KaleidoApplication(this, eventBus, getActivityManager(),  placeController, historyMapper, historyHandler);
    }

    /**
     * Inicializa el manejador de excepciones.
     */
    private void initializeExceptionHandler() {
        GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void onUncaughtException(Throwable e) {
                while (e instanceof UmbrellaException) {
                    e = ((UmbrellaException) e).getCauses().iterator().next();
                }
                String message = e.getMessage();
                if (message == null) {
                    message = e.toString();
                }
                Log.error("Uncaught exception", e);
                Window.alert("An unexpected error occurred: " + e);
            }
        });
    }

    private ActivityManager getActivityManager() {
        if (activityManager == null) {
            activityManager = new ActivityManager(createActivityMapper(), eventBus);
        }
        return activityManager;
    }

    /**
     * ActivityMapper determines an Activity to run for a particular place, configures the {@link #getActivityManager()}
     */
    private ActivityMapper createActivityMapper() {
        return new DataPanelActivityMapper(this);
    }
}
